package com.wstuo.schema;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Properties;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.jbpm.pvm.internal.id.PropertyImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import com.wstuo.configData.service.IConfigDataLoaderService;
import com.wstuo.common.config.moduleManage.entity.ModuleManage;
import com.wstuo.common.config.moduleManage.service.IModuleManageService;
import com.wstuo.common.security.dto.UserDTO;
import com.wstuo.common.security.utils.AppContext;
import com.wstuo.common.util.AppliactionBaseListener;
import com.wstuo.common.util.StringUtils;
import com.wstuo.common.config.moduleManage.dto.ModuleManageDTO;

public class SchemaTool implements ISchemaTool{
	public static final String URL = "dataSource.url";
	public static final String SERVERNAME="dataSource.serverName";
	
	public void createDatabase(String tenantIdentifier) throws SQLException{
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		DriverManagerDataSource dataSourceBean = getDataSourceBean(ctx);
		LocalSessionFactoryBean factoryBean = getFactoryBean(ctx);
		Configuration cfg =  factoryBean.getConfiguration();
		dataSourceBean = setDataSourceUrl(dataSourceBean, cfg, "");
		
		final Connection connection = dataSourceBean.getConnection();
		connection.createStatement().execute("create database " + tenantIdentifier);
	}
	
	public void createSchema(String tenantIdentifier) throws SQLException{
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		DriverManagerDataSource dataSourceBean = getDataSourceBean(ctx);
		LocalSessionFactoryBean factoryBean = getFactoryBean(ctx);
		Configuration cfg =  factoryBean.getConfiguration();
		dataSourceBean = setDataSourceUrl(dataSourceBean, cfg, tenantIdentifier);

		SchemaExport dbExport = new SchemaExport(cfg,dataSourceBean.getConnection());
	    dbExport.setFormat(true);
		dbExport.create(false, true);
	}
	
	public void updateSchema(String tenantIdentifier) throws SQLException{
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		DriverManagerDataSource dataSourceBean = getDataSourceBean(ctx);
		LocalSessionFactoryBean factoryBean = getFactoryBean(ctx);
		Configuration cfg =  getConfiguration(dataSourceBean, factoryBean, tenantIdentifier);
		
		SchemaUpdate dbUpdate = new SchemaUpdate(cfg);
		dbUpdate.setFormat(true);
		dbUpdate.execute(false, true);
	}
	
	public void configDataLoader(String tenantIdentifier,String language ,UserDTO userDTO) throws SQLException{
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		if(ctx!=null){
			setTenantIdentifier(tenantIdentifier,ctx);
			/*JBPM4_PROPERTY 数据初始化*/
			jbpmInit(ctx);
			//需要加载请求模块
			moduleManageInit(ctx);
			/*基础数据初始化*/
			configDataInit(language,ctx,userDTO);
		}
	}
	
	/**
	 * 配置文件初始化
	 * @param tenantIdentifier
	 */
	public void configureFileInit(String tenantIdentifier){
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		setTenantIdentifier(tenantIdentifier, ctx);
		IConfigDataLoaderService configDataLoaderService = (IConfigDataLoaderService)ctx.getBean("configDataLoaderService");
		configDataLoaderService.preparingConfigure();
	}
	
	public void tenantDataInit(String tenantIdentifier,String language,UserDTO userDTO) throws SQLException{
		ApplicationContext ctx =AppliactionBaseListener.ctx;
		if(ctx!=null){
			DriverManagerDataSource dataSourceBean = getDataSourceBean(ctx);
			if(null != dataSourceBean){
				LocalSessionFactoryBean factoryBean = getFactoryBean(ctx);
				Configuration cfg =  factoryBean.getConfiguration();
				dataSourceBean = setDataSourceUrl(dataSourceBean, cfg, "");
				
				final Connection connection = dataSourceBean.getConnection();
				connection.createStatement().execute("create database " + tenantIdentifier);
				
				
				dataSourceBean = setDataSourceUrl(dataSourceBean, cfg, tenantIdentifier);
				SchemaExport dbExport = new SchemaExport(cfg,dataSourceBean.getConnection());
			    dbExport.setFormat(true);
				dbExport.create(false, true);
			
			
				setTenantIdentifier(tenantIdentifier,ctx);
				/*JBPM4_PROPERTY 数据初始化*/
				jbpmInit(ctx);
				//需要加载请求模块
				moduleManageInit(ctx);
				/*基础数据初始化*/
				configDataInit(language,ctx,userDTO);
			}
		}
	}
	/**
	 * get DataSourceBean
	 * @param ctx
	 * @return
	 */
	private DriverManagerDataSource getDataSourceBean(ApplicationContext ctx){
		DriverManagerDataSource dataSourceBean = (DriverManagerDataSource)ctx.getBean("dataSource");
		return dataSourceBean;
	}
	/**
	 * get FactoryBean
	 * @param ctx
	 * @return
	 */
	private LocalSessionFactoryBean getFactoryBean(ApplicationContext ctx){
		LocalSessionFactoryBean factoryBean = (LocalSessionFactoryBean)ctx.getBean("&sessionFactory");
		return factoryBean;
	}
	
	/**
	 * set DataSourceUrl
	 * @param dataSourceBean
	 * @param cfg
	 * @param tenantIdentifier
	 * @return
	 */
	private DriverManagerDataSource setDataSourceUrl(DriverManagerDataSource dataSourceBean,Configuration cfg ,String tenantIdentifier){
		Properties pro = cfg.getProperties();
		String url = (String) pro.get(URL);
		String serverName =(String) pro.get(SERVERNAME);
		if(StringUtils.hasText(tenantIdentifier)){
			dataSourceBean.setUrl(url+serverName+"/"+tenantIdentifier);
		}else{
			dataSourceBean.setUrl(url+serverName);
		}
		return  dataSourceBean;
	}
	
	/**
	 * get Configuration
	 * @param dataSourceBean
	 * @param factoryBean
	 * @param tenantIdentifier
	 * @return
	 * @throws SQLException
	 */
	private Configuration getConfiguration(DriverManagerDataSource dataSourceBean,LocalSessionFactoryBean factoryBean ,String tenantIdentifier) throws SQLException{
		Configuration cfg =  factoryBean.getConfiguration();
		
		dataSourceBean = setDataSourceUrl(dataSourceBean, cfg, tenantIdentifier);
		
		Properties connectionProps = factoryBean.getHibernateProperties();
		connectionProps.put( Environment.DRIVER, DriverManager.getDriver(dataSourceBean.getUrl()).getClass().getName());
		connectionProps.put( Environment.URL, dataSourceBean.getUrl());
		connectionProps.put( Environment.USER, dataSourceBean.getUsername());
		connectionProps.put( Environment.PASS, dataSourceBean.getPassword() );
		cfg.getProperties().putAll(connectionProps);
		cfg.getProperties().remove(Environment.MULTI_TENANT);
		cfg.getProperties().remove(Environment.MULTI_TENANT_IDENTIFIER_RESOLVER);
		cfg.getProperties().remove(Environment.MULTI_TENANT_CONNECTION_PROVIDER);
	    
		return cfg;
	}
	/**
	 * set TenantIdentifier
	 * @param tenantIdentifier
	 * @param ctx
	 */
	private void setTenantIdentifier(String tenantIdentifier,ApplicationContext ctx){
		AppContext appContext=(AppContext)ctx.getBean("appctx");
		appContext.setAttribute("tenantId", tenantIdentifier);
	}
	/**
	 * JBPM4_PROPERTY 数据初始化
	 * @param ctx
	 */
	private void jbpmInit(ApplicationContext ctx){
		/*JBPM4_PROPERTY 数据初始化*/
		LocalSessionFactoryBean factoryBean = getFactoryBean(ctx);
		SessionFactory sessionFactory = factoryBean.getObject();
		Session session = sessionFactory.openSession();
		Transaction tx = session.beginTransaction();
		PropertyImpl property = new PropertyImpl(PropertyImpl.NEXT_DBID_KEY, "0");
		session.save(property);
		tx.commit();
		session.close();
	}
	/**
	 * 加载请求模块
	 * @param ctx
	 */
	private void moduleManageInit(ApplicationContext ctx){
		//需要加载请求模块
		IModuleManageService moduleManageService=(IModuleManageService) ctx.getBean("moduleManageService");
		ModuleManageDTO moduleManage=new ModuleManageDTO();
		moduleManage.setModuleName("request");
		moduleManage.setShowSort(1L);
		moduleManage.setDataFlag((byte) 1);
		moduleManage.setCreateTime(new Date());
		moduleManageService.saveModule(moduleManage);
	}
	/**
	 * 基础数据初始化
	 * @param language
	 * @param ctx
	 */
	private void configDataInit(String language,ApplicationContext ctx,UserDTO userDTO){
		//基础数据初始化
		IConfigDataLoaderService configDataLoaderService = (IConfigDataLoaderService)ctx.getBean("configDataLoaderService");
		configDataLoaderService.importAllConfigData(language, userDTO);
	}
	
}
